package com.arcaneshift.util;

import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.arcaneshift.model.action.game.Player;
import com.arcaneshift.model.action.game.QueuePlayer;
import com.common.util.MemoryCache;
import com.common.util.SetCache;

public class PlayerCacheContainer {

	private static final String PLAYER_VALUES = "PlayerValues";
	private static final SetCache setCache;
	private static final MemoryCache<String, QueuePlayer> container;
	private static final Long EXPIRE_TIME = 900000L;

	static {
		setCache = new SetCache(PLAYER_VALUES);
		container = new MemoryCache<String, QueuePlayer>();
	}

	private PlayerCacheContainer() {}
	
	/**
	 * Add a Player in the container list.
	 * 
	 * @param player
	 */
	public static void addPlayer(Player player) {
		QueuePlayer queuePlayer = new QueuePlayer(player, new GregorianCalendar());
		
		container.put(queuePlayer.getPlayer().getSession().getUserId().toString(), queuePlayer);
		setCache.add(queuePlayer.getPlayer().getSession().getUserId().toString());
	}
	
	public static void updateQueuePlayer(QueuePlayer queuePlayer) {
		queuePlayer.setTime(new GregorianCalendar());
		container.put(queuePlayer.getPlayer().getSession().getUserId().toString(), queuePlayer);
	}
	
	public static void updatePlayer(Player player) {
		Map<String, QueuePlayer> map = container.getAll(setCache.getValues());
		Set<Map.Entry<String, QueuePlayer>> entries = map.entrySet();
		
		Iterator<Map.Entry<String, QueuePlayer>> iterator = entries.iterator();
		while (iterator.hasNext()) {
			QueuePlayer queuePlayer = iterator.next().getValue();
			if (queuePlayer.getPlayer().getSession().getId().equals(player.getSession().getId())) {
				queuePlayer.setPlayer(player);
				updateQueuePlayer(queuePlayer);
			}
		}
	}
	
	public static List<QueuePlayer> getAll() {
		Map<String, QueuePlayer> map = container.getAll(setCache.getValues());
		Set<Map.Entry<String, QueuePlayer>> entries = map.entrySet();
		List<QueuePlayer> values = new ArrayList<QueuePlayer>();
		
		Iterator<Map.Entry<String, QueuePlayer>> iterator = entries.iterator();
		while (iterator.hasNext()) {
			values.add(iterator.next().getValue());
		}
		return values;
	}
	
	/**
	 * Delete the Player, from the Player Queue.
	 * 
	 * @param player
	 */
	public static void deletePlayer(Player player) {
		Map<String, QueuePlayer> map = container.getAll(setCache.getValues());
		Set<Map.Entry<String, QueuePlayer>> entries = map.entrySet();
		
		Iterator<Map.Entry<String, QueuePlayer>> iterator = entries.iterator();
		while (iterator.hasNext()) {
			QueuePlayer queuePlayer = iterator.next().getValue();
			if (queuePlayer.getPlayer().getSession().getId().equals(player.getSession().getId())) {
				container.remove(queuePlayer);
				setCache.remove(player.getSession().getUserId().toString());
			}
		}
	}
	
	public static void deleteQueuePlayer(QueuePlayer queuePlayer) {
		container.remove(queuePlayer);
	}
	
	/**
	 * Get a Player by it's userId.
	 * 
	 * @param userId
	 * @return player/null
	 */
	public static Player getPlayer(String sessionId) {
		Map<String, QueuePlayer> map = container.getAll(setCache.getValues());
		Set<Map.Entry<String, QueuePlayer>> entries = map.entrySet();
		
		Iterator<Map.Entry<String, QueuePlayer>> iterator = entries.iterator();
		while (iterator.hasNext()) {
			QueuePlayer queuePlayer = iterator.next().getValue();
			if (queuePlayer.getPlayer().getSession().getId().equals(sessionId)) {
				return queuePlayer.getPlayer();
			}
		}
		return null;
	}
	
	public static Player getPlayer(Long playerId) {
		Map<String, QueuePlayer> map = container.getAll(setCache.getValues());
		Set<Map.Entry<String, QueuePlayer>> entries = map.entrySet();
		
		Iterator<Map.Entry<String, QueuePlayer>> iterator = entries.iterator();
		while (iterator.hasNext()) {
			QueuePlayer queuePlayer = iterator.next().getValue();
			if (queuePlayer.getPlayer().getSession().getUserId() == playerId) {
				return queuePlayer.getPlayer();
			}
		}
		return null;
	}
	
	/**
	 * Get the first Player that is not assigned to a game
	 * 
	 * @return player/null
	 */
	public static Player getAvailablePlayer() {
		Map<String, QueuePlayer> map = container.getAll(setCache.getValues());
		Set<Map.Entry<String, QueuePlayer>> entries = map.entrySet();
		
		Iterator<Map.Entry<String, QueuePlayer>> iterator = entries.iterator();
		while (iterator.hasNext()) {
			QueuePlayer queuePlayer = iterator.next().getValue();
			if (!queuePlayer.getPlayer().isInGame()) {
				return queuePlayer.getPlayer();
			}
		}
		return null;
	}
	
	/**
	 * Check if the queue player with the given player id exists in the PlayerContainer
	 * and if it does, refresh it's timer.
	 * 
	 * @param sessionId
	 * @return true/false
	 */
	public static boolean containsAndRefresh(String sessionId) {
		Map<String, QueuePlayer> map = container.getAll(setCache.getValues());
		Set<Map.Entry<String, QueuePlayer>> entries = map.entrySet();
		
		Iterator<Map.Entry<String, QueuePlayer>> iterator = entries.iterator();
		while (iterator.hasNext()) {
			QueuePlayer queuePlayer = iterator.next().getValue();
			if (queuePlayer.getPlayer().getSession().getId().equals(sessionId)) {
				updateQueuePlayer(queuePlayer);
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Delete all the queue players that are idle for more than EXPIRED_TIME time.
	 */
	public static void deleteExpiredQueuePlayers() {
		Map<String, QueuePlayer> map = container.getAll(setCache.getValues());
		Set<Map.Entry<String, QueuePlayer>> entries = map.entrySet();
		long time = new GregorianCalendar().getTimeInMillis();
		
		Iterator<Map.Entry<String, QueuePlayer>> iterator = entries.iterator();
		while (iterator.hasNext()) {
			QueuePlayer queuePlayer = iterator.next().getValue();
			if (time - queuePlayer.getTime().getTimeInMillis() > EXPIRE_TIME) {
				deleteQueuePlayer(queuePlayer);
			}
		}
	}
}